﻿#include "TxtTo2DSurfaceGenerator.h"
#include <vtkActor.h>  
#include <vtkTable.h>  
#include <QDebug>  
#include <vtkProperty.h>  
#include <vtkRenderer.h>  
#include <vtkPointData.h>  
#include <vtkDelaunay2D.h>  
#include <vtkLookupTable.h>  
#include <vtkRenderWindow.h>  
#include <vtkTextProperty.h>
#include <vtkScalarBarActor.h>  
#include <vtkPolyDataMapper.h>  
#include <vtkDelimitedTextReader.h>
#include <vtkRenderWindowInteractor.h>  
#include "BaseModule/IBaseSignal.h"  

namespace
{
    const double EPSILON = 1e-6;

    bool isEqual(double a, double b) {
        return fabs(a - b) < EPSILON;
    }
}

namespace pst
{
    TxtTo2DSurfaceGenerator::TxtTo2DSurfaceGenerator(QObject* parent)
        : QObject(parent)
        , m_scalarRange{ 0.0,0.0 }
        , m_filename{ }
    {
    }

    void TxtTo2DSurfaceGenerator::setFilename(const QString& filename)
    {
        m_filename = filename;
    }

    QString TxtTo2DSurfaceGenerator::getFilename() const
    {
        return m_filename;
    }

    bool TxtTo2DSurfaceGenerator::update()
    {
        auto isSuccess = readCSV(m_filename);
        if (!isSuccess)
        {
            return false;
        }
        createVTKPolyData();
        createScalarBar();
        return true;
    }

    vtkSmartPointer<vtkActor> TxtTo2DSurfaceGenerator::getActor()
    {
        return m_actor;
    }

    vtkSmartPointer<vtkScalarBarActor> TxtTo2DSurfaceGenerator::getScalarBar()
    {
        return m_scalarBar;
    }

    bool TxtTo2DSurfaceGenerator::readCSV(const QString& filename)
    {
        vtkNew<vtkDelimitedTextReader> reader;
        reader->SetFileName(filename.toStdString().c_str());
        reader->SetFieldDelimiterCharacters(",");
        reader->SetHaveHeaders(true);
        reader->Update();

        m_dataTable = reader->GetOutput();

        if (m_dataTable->GetNumberOfColumns() != 4)
        {
            auto errorMes = "Invalid number of columns.Expected 4.";
            emit IBaseSignalInstance->signal_sendErrorMessageToUI(errorMes);
            qDebug() << errorMes;
            return false;
        }
        return true;
    }

    void TxtTo2DSurfaceGenerator::createVTKPolyData()
    {
        vtkNew<vtkPoints> points;
        vtkNew<vtkDoubleArray> fieldArray;
        fieldArray->SetName("field");

        //for (vtkIdType i = 0; i < m_dataTable->GetNumberOfRows(); ++i)
        //{
        //    double x = m_dataTable->GetValue(i, 0).ToDouble();
        //    double y = m_dataTable->GetValue(i, 1).ToDouble();
        //    double field = m_dataTable->GetValue(i, 2).ToDouble();
        //    points->InsertNextPoint(x, y, 0.0); // z is set to 0  
        //    fieldArray->InsertNextValue(field);
        //}
        for (vtkIdType i = 0; i < m_dataTable->GetNumberOfRows(); ++i)
        {
            double x = m_dataTable->GetValue(i, 0).ToDouble();
            if (isEqual(x, 0.0))
            {
                double y = m_dataTable->GetValue(i, 1).ToDouble();
                double z = m_dataTable->GetValue(i, 2).ToDouble();
                double field = m_dataTable->GetValue(i, 3).ToDouble();
                points->InsertNextPoint(y, z, 0.0);
                fieldArray->InsertNextValue(field);
            }
        }
        m_scalarRange[0] = fieldArray->GetRange()[0];
        m_scalarRange[1] = fieldArray->GetRange()[1];
        vtkNew<vtkPolyData> polyData;
        polyData->SetPoints(points);
        polyData->GetPointData()->AddArray(fieldArray);
        polyData->GetPointData()->SetActiveAttribute(
            0, vtkDataSetAttributes::AttributeTypes::SCALARS);
        vtkNew<vtkDelaunay2D> delaunay;
        delaunay->SetInputData(polyData);
        delaunay->Update();

        vtkNew<vtkPolyDataMapper> mapper;
        mapper->SetInputConnection(delaunay->GetOutputPort());
        mapper->SetScalarModeToUsePointData();
        mapper->SetColorModeToMapScalars();
        mapper->SetUseLookupTableScalarRange(1);
        mapper->ScalarVisibilityOn();
        createLookupTable();
        mapper->SetLookupTable(m_lookupTable);
        mapper->Update();

        m_actor = vtkSmartPointer<vtkActor>::New();
        m_actor->SetMapper(mapper);
    }

    vtkSmartPointer<vtkLookupTable>
        TxtTo2DSurfaceGenerator::createLookupTable()
    {
        m_lookupTable = vtkSmartPointer<vtkLookupTable>::New();
        m_lookupTable->SetNumberOfColors(256);
        m_lookupTable->SetRange(m_scalarRange);
        m_lookupTable->Build();
        return m_lookupTable;
    }

    void TxtTo2DSurfaceGenerator::createScalarBar()
    {
        m_scalarBar = vtkSmartPointer<vtkScalarBarActor>::New();
        m_scalarBar->SetLookupTable(m_lookupTable);
        m_scalarBar->SetTitle("Field Value");
        m_scalarBar->GetLabelTextProperty()->SetFontSize(12);
        m_scalarBar->GetTitleTextProperty()->SetFontSize(14);
        m_scalarBar->SetPosition(0.85, 0.1);
        m_scalarBar->SetWidth(0.1);
        m_scalarBar->SetHeight(0.8);
    }
}
